﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using Alchemy;
using Alchemy.Classes;
using Newtonsoft.Json;
using Rebazza.Server.Interfaces;

namespace Rebazza.Server.Entities
{
    public abstract class BaseGameServer : IBaseGameServer
    {
        public event EventHandler<ServerEventArgs> ClientConnected;
        public event EventHandler<ServerEventArgs> ClientDisconnected;
        public event EventHandler<ServerEventArgs> ReceiveFromClient;
        public event EventHandler<ServerEventArgs> SendToClient;

        private readonly ConcurrentDictionary<BaseUser, string> onlineUsers;
        private readonly int gamePort;
        private WebSocketServer aServer;

        /// <summary>
        /// Initializes a new instance of the GameServer class
        /// </summary>
        /// <param name="gamePort"></param>
        protected BaseGameServer(int gamePort)
        {
            this.gamePort = gamePort;
            onlineUsers = new ConcurrentDictionary<BaseUser, string>();
        }

        /// <summary>
        /// Starts GameSever
        /// </summary>
        public void Start()
        {
            aServer = new WebSocketServer(gamePort, IPAddress.Any)
                              {
                                  OnConnect = OnConnect,
                                  OnReceive = OnReceive,
                                  //OnSend = OnSend,
                                  OnDisconnect = OnDisconnect
                              };

            aServer.Start();
        }

        public void Stop()
        {
            aServer.Stop();
        }

        public void Send(BaseUser user, Message message)
        {
            var json = JsonConvert.SerializeObject(message);
            user.Context.Send(json);
        }

        public void OnConnect(UserContext context)
        {
            var user = new BaseUser(context);
            onlineUsers.TryAdd(user, string.Empty);
            ClientConnected(this, new ServerEventArgs(user));
        }

        public void OnReceive(UserContext context)
        {
            ReceiveFromClient(this, new ServerEventArgs(new BaseUser(context)));
        }

        public void OnSend(UserContext context)
        {
            var user = new BaseUser(context);
            SendToClient(this, new ServerEventArgs(user));
        }

        public void OnDisconnect(UserContext context)
        {
            var user = onlineUsers.Keys.Single(x => x.Context.ClientAddress == context.ClientAddress);
            string trash;
            var result = onlineUsers.TryRemove(user, out trash);
            ClientDisconnected(this, new ServerEventArgs(user));
        }
    }
}
